package com.qjcc.util;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;


import com.qjcc.R;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.StringPart;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.protocol.HTTP;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Android调用http请求
 * Created by WangKun on 2015/09/08.
 */
public class HttpAccessUtilsVersion2 {
    // 含有3个线程的线程池
    private static final String APPLICATION_JSON = "application/json; charset=utf-8";

    private static final String CONTENT_TYPE_TEXT_JSON = "text/json";
    private static final ExecutorService executorService = Executors.newFixedThreadPool(5);
    public static final String UTF_8 = "UTF-8";
    private final static int TIMEOUT_CONNECTION = 20000;
    private final static int TIMEOUT_SOCKET = 20000;
    private final static int RETRY_TIME = 3;
    private final static int TOAST_TIP_TIME = 3000;
    //    private static final String HOST = AppContext.getAppContext().getResources().getString(R.string.domain);
    private static String appCookie;
    private static String appUserAgent;
    //用户缓存信息
    private static String userSessionId;
    //http连接提示
//    private static String MSG_CON_TIMEOUT = AppContext.getAppContext().getResources().getString(R.string.msg_con_timeout);
//    private static String MSG_CON_ERR = AppContext.getAppContext().getResources().getString(R.string.msg_con_err);
//    private static String MSG_RESQ_TIMEOUT = AppContext.getAppContext().getResources().getString(R.string.msg_resq_timeout);
//    private static String MSG_NO_NETWORK = AppContext.getAppContext().getResources().getString(R.string.msg_no_network);

    /**
     * 普通请求
     *
     * @param url                指定待访问url地址
     * @param paramsMap          传入参数
     * @param httpAccessCallBack 回调接口
     *                           如果请求服务成功则返回服务器数据，如果失败或有异常则返回{ok:false,msg:[具体原因]}
     */
    public static void callHttpAccess(Context context, String url, Map<String, String> paramsMap, HttpAccessCallBack httpAccessCallBack) {
        callHttpAccess(context, url, paramsMap, null, null, httpAccessCallBack);
    }

    /**
     * 下载文件
     *
     * @param url                指定待访问url地址
     * @param paramsMap          传入参数
     * @param uri                保存文件的uri
     * @param httpAccessCallBack 回调接口
     *                           如果请求服务成功则返回服务器数据，如果失败或有异常则返回{ok:false,msg:[具体原因]}
     */
    public static void callHttpAccess(Context context, String url, Map<String, String> paramsMap, Uri uri, HttpAccessCallBack httpAccessCallBack) {
        callHttpAccess(context, url, paramsMap, null, uri, httpAccessCallBack);
    }

    /**
     * 上传文件
     *
     * @param url                指定待访问url地址
     * @param paramsMap          传入参数
     * @param fileMap            传入文件参数
     * @param httpAccessCallBack 回调接口
     *                           如果请求服务成功则返回服务器数据，如果失败或有异常则返回{ok:false,msg:[具体原因]}
     */
    public static void callHttpAccess(Context context, String url, Map<String, String> paramsMap, Map<String, File> fileMap, HttpAccessCallBack httpAccessCallBack) {
        callHttpAccess(context, url, paramsMap, fileMap, null, httpAccessCallBack);
    }

    /**
     * get请求
     *
     * @param context
     * @param url
     * @param httpAccessCallBack
     */
    public static void callHttpAccess(Context context, String url, HttpAccessCallBack httpAccessCallBack) {
        callHttpAccess(context, url, null, null, null, "get", httpAccessCallBack);
    }

    /**
     * 访问指定url地址
     *
     * @param url                指定待访问url地址
     * @param paramsMap          传入参数
     * @param fileMap            传入文件参数(上传文件)
     * @param uri                保存文件的uri(下载文件)
     * @param httpAccessCallBack 回调接口
     *                           如果请求服务成功则返回服务器数据，如果失败或有异常则返回{ok:false,msg:[具体原因]}
     */
    public static void callHttpAccess(Context context, String url, Map<String, String> paramsMap, Map<String, File> fileMap, Uri uri, HttpAccessCallBack httpAccessCallBack) {
        if (NetWorkUtil.isConnect(context)) {//检查设备网络是否可用
            // 添加传入参数
            MultipartEntity multipartEntity = null;
            List<NameValuePair> paramsList = null;
            if (fileMap != null) {
                multipartEntity = new MultipartEntity();
                for (Iterator<Map.Entry<String, File>> iterator = fileMap.entrySet().iterator(); iterator.hasNext(); ) {
                    Map.Entry<String, File> entry = iterator.next();
                    multipartEntity.addPart(entry.getKey(), new FileBody(entry.getValue()));
                }
                if (paramsMap != null) {
                    for (Iterator<Map.Entry<String, String>> it = paramsMap.entrySet().iterator(); it.hasNext(); ) {
                        Map.Entry<String, String> entry = it.next();
                        try {
                            multipartEntity.addPart(entry.getKey(), new StringBody(String.valueOf(entry.getValue()), Charset.forName(UTF_8)));
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                    }
                }
            } else if (null != paramsMap) {
                paramsList = new ArrayList<NameValuePair>();
                for (Iterator<Map.Entry<String, String>> it = paramsMap.entrySet().iterator(); it.hasNext(); ) {
                    Map.Entry<String, String> entry = it.next();
                    paramsList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                }
            }
            callHttpAccess(context, url, paramsList, multipartEntity, uri, "post", httpAccessCallBack);
        } else {
            UIHelper.ToastMessage(context, context.getString(R.string.msg_no_network));
        }
    }

    public static void callHttpAccess(final Context context, final String url, final List<NameValuePair> paramsList, final MultipartEntity multipartEntity, final Uri uri, final String methodType, final HttpAccessCallBack httpAccessCallBack) {
        userSessionId = SharedPreferencesUtil.getSessionId(context);
        if (NetWorkUtil.isConnect(context)) {//检查设备网络是否可用
            // 用于子线程与主线程通信的Handler
            final Handler mHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    // 将返回值回调到callBack的参数中
                    httpAccessCallBack.callBack(msg.obj);
                }

            };

            // 开启线程去访问http
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    StringBuilder total = new StringBuilder();
                    try {
                        DefaultHttpClient client = new DefaultHttpClient();
                        // 请求超时
                        client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, TIMEOUT_CONNECTION);
                        // 读取超时
                        client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, TIMEOUT_SOCKET);
                        HttpResponse httpResponse = null;
                        if (uri != null || "get".equals(methodType)) {
                            HttpGet httpGet = new HttpGet(url);
                            //加入token参数
//                            .handleToken(context, httpGet);

                            httpResponse = client.execute(httpGet);
                        } else {
                            HttpPost httpRequest = new HttpPost(url);
                            //加入token参数
//                            AccessTokenUtil.handleToken(context, httpRequest);

                            if (paramsList != null) {
                                httpRequest.setEntity(new UrlEncodedFormEntity(paramsList, HTTP.UTF_8));
                            } else if (multipartEntity != null) {
                                httpRequest.setEntity(multipartEntity);
                            }
                            //设置http头，以保持http请求session
                            if (userSessionId != null) {
                                httpRequest.setHeader("Cookie", userSessionId);
                            } else {
                                Log.e("tag", "sessionId为空");
                            }
                            httpResponse = client.execute(httpRequest);
                        }
                        if (httpResponse.getStatusLine().getStatusCode() == 200) {
                            if (uri == null) {
                                String line = "";
                                BufferedReader rd = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));
                                while ((line = rd.readLine()) != null) {
                                    total.append(line);
                                }
                            } else {
                                OutputStream os = context.getContentResolver().openOutputStream(uri);
                                InputStream is = httpResponse.getEntity().getContent();
                                int len = 0;
                                byte[] bytes = new byte[1024];
                                while ((len = is.read(bytes)) > 0) {
                                    os.write(bytes, 0, len);
                                }
                                os.close();
                                is.close();
                                Log.e("tag", uri.toString());

                            }
                        } else {
                            total.append("{\"ok\":false,\"msg\":\"" + context.getString(R.string.url_err) + "！：" + url + context.getString(R.string.err_code) + "：" + httpResponse.getStatusLine().getStatusCode() + "\"}");
                            Log.i("HttpAccessUtils", context.getString(R.string.url_err) + "！：" + url);
                        }
                    } catch (ConnectTimeoutException e1) {
                        total.append("{\"ok\":false,\"msg\":\"" + context.getString(R.string.msg_con_timeout) + "\"}");
                    } catch (InterruptedIOException e2) {
                        total.append("{\"ok\":false,\"msg\":\"" + context.getString(R.string.msg_resq_timeout) + "\"}");
                    } catch (ConnectException e3) {
                        total.append("{\"ok\":false,\"msg\":\"" + context.getString(R.string.msg_con_err) + "\"}");
                    } catch (IOException e) {
                        total.append("{\"ok\":false,\"msg\":\"" + e.getLocalizedMessage() + "\"}");
                        Log.e("HttpAccessUtils", "IOException" + context.getString(R.string.exception), e);
                    } finally {
                        // 将获取的消息利用Handler发送到主线程
                        String result = total.toString();
                        result = result.replaceAll("\"\\w*\":null,*", "");
                        result = result.replace(",}", "}");
                        mHandler.sendMessage(mHandler.obtainMessage(0, result));
                    }
                }
            });

        } else {
            UIHelper.ToastMessage(context, context.getString(R.string.msg_no_network));
        }
    }

    /**
     * 访问指定url地址
     *
     * @param url                指定待访问url地址
     * @param json               传入参数
     * @param httpAccessCallBack 回调接口
     *                           如果请求服务成功则返回服务器数据，如果失败或有异常则返回{ok:false,msg:[具体原因]}
     */
    public static void callHttpAccess4Json(final Context context, final String url, final String json, final HttpAccessCallBack httpAccessCallBack) {
        userSessionId = SharedPreferencesUtil.getSessionId(context);
        if (NetWorkUtil.isConnect(context)) {//检查设备网络是否可用

            // 用于子线程与主线程通信的Handler
            final Handler mHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    // 将返回值回调到callBack的参数中
                    httpAccessCallBack.callBack(msg.obj);
                }

            };

            // 开启线程去访问http
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    StringBuilder total = new StringBuilder();
                    HttpPost httpRequest = new HttpPost(url);
                    httpRequest.addHeader(HTTP.CONTENT_TYPE, APPLICATION_JSON);
                    //加入token参数
//                    AccessTokenUtil.handleToken(context, httpRequest);

                    try {
                        //设置http头，以保持http请求session
                        if (userSessionId != null) {
                            httpRequest.setHeader("Cookie", userSessionId);
                        }

                        BasicHttpParams httpParams = new BasicHttpParams();
                        httpParams.setParameter("charset", "UTF-8");
                        HttpConnectionParams.setConnectionTimeout(httpParams, TIMEOUT_CONNECTION);  //毫秒
                        HttpConnectionParams.setSoTimeout(httpParams, TIMEOUT_SOCKET);
                        DefaultHttpClient client = new DefaultHttpClient(httpParams);

                        httpRequest.setEntity(new StringEntity(json.toString(), "UTF-8"));

                        HttpResponse httpResponse = client.execute(httpRequest);
                        if (httpResponse.getStatusLine().getStatusCode() == 200) {
                            String line = "";
                            BufferedReader rd = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));
                            while ((line = rd.readLine()) != null) {
                                total.append(line);
                            }
                        } else {
                            total.append("{\"ok\":false,\"msg\":\"" + context.getString(R.string.url_err) + "！：" + url + context.getString(R.string.err_code) + "：" + httpResponse.getStatusLine().getStatusCode() + "\"}");
                            Log.i("HttpAccessUtils", context.getString(R.string.url_err) + "！：" + url);
                        }
                    } catch (ConnectTimeoutException e1) {
                        total.append("{\"ok\":false,\"msg\":\"" + context.getString(R.string.msg_con_timeout) + "\"}");
                    } catch (InterruptedIOException e2) {
                        total.append("{\"ok\":false,\"msg\":\"" + context.getString(R.string.msg_resq_timeout) + "\"}");
                    } catch (ConnectException e3) {
                        total.append("{\"ok\":false,\"msg\":\"" + context.getString(R.string.msg_con_err) + "\"}");
                    } catch (IOException e) {
                        total.append("{\"ok\":false,\"msg\":\"" + e.getLocalizedMessage() + "\"}");
                        Log.e("HttpAccessUtils", "IOException" + context.getString(R.string.exception), e);
                    } finally {
                        // 将获取的消息利用Handler发送到主线程
                        mHandler.sendMessage(mHandler.obtainMessage(0, total));
                    }
                }
            });
        } else {
            UIHelper.ToastMessage(context, context.getString(R.string.msg_no_network));
        }
    }

    /**
     * 定义返回接口
     */
    public interface HttpAccessCallBack {
        void callBack(Object result);
    }

    public static void cleanCookie() {
        appCookie = "";
    }

    private static String getUserAgent(Context context) {
        if (appUserAgent == null || appUserAgent == "") {
            StringBuilder ua = new StringBuilder("SCTF");
            ua.append('/' + getPackageInfo(context).versionName + '_' + getPackageInfo(context).versionCode);//App版本
            ua.append("/Android");//手机系统平台
            ua.append("/" + android.os.Build.VERSION.RELEASE);//手机系统版本
            ua.append("/" + android.os.Build.MODEL); //手机型号
//			ua.append("/"+appContext.getAppId());//客户端唯一标识
            appUserAgent = ua.toString();
        }
        return appUserAgent;
    }

    public static PackageInfo getPackageInfo(Context context) {
        PackageInfo info = null;
        try {
            info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace(System.err);
        }
        if (info == null) info = new PackageInfo();
        return info;
    }

    private static HttpClient getHttpClient() {
        HttpClient httpClient = new HttpClient();
        // 设置 HttpClient 接收 Cookie,用与浏览器一样的策略
        httpClient.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
        // 设置 默认的超时重试处理策略
        httpClient.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
        // 设置 连接超时时间
        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(TIMEOUT_CONNECTION);
        // 设置 读数据超时时间
        httpClient.getHttpConnectionManager().getParams().setSoTimeout(TIMEOUT_SOCKET);
        // 设置 字符集
        httpClient.getParams().setContentCharset(UTF_8);
        return httpClient;
    }

    private static GetMethod getHttpGet(Context context, String url, String cookie, String userAgent) {
        GetMethod httpGet = new GetMethod(url);
        // 设置 请求超时时间
        httpGet.getParams().setSoTimeout(TIMEOUT_SOCKET);
        httpGet.setRequestHeader("Host", context.getString(R.string.domain));
        httpGet.setRequestHeader("Connection", "Keep-Alive");
        httpGet.setRequestHeader("Cookie", cookie);
        httpGet.setRequestHeader("User-Agent", userAgent);
        return httpGet;
    }

    private static PostMethod getHttpPost(Context context, String url, String cookie, String userAgent) {
        PostMethod httpPost = new PostMethod(url);
        // 设置 请求超时时间
        httpPost.getParams().setSoTimeout(TIMEOUT_SOCKET);
        httpPost.setRequestHeader("Host", context.getString(R.string.domain));
        httpPost.setRequestHeader("Connection", "Keep-Alive");
        httpPost.setRequestHeader("Cookie", cookie);
        httpPost.setRequestHeader("User-Agent", userAgent);
        return httpPost;
    }

    /**
     * get请求URL
     *
     * @param url
     */
    public static InputStream http_get(Context context, String url) {
        //System.out.println("get_url==> "+url);
//		String cookie = getCookie(appContext);
        String userAgent = getUserAgent(context);

        HttpClient httpClient = null;
        GetMethod httpGet = null;

        String responseBody = "";
        int time = 0;
        do {
            try {
                httpClient = getHttpClient();
                httpGet = getHttpGet(context, url, "", userAgent);
                int statusCode = httpClient.executeMethod(httpGet);
                if (statusCode != HttpStatus.SC_OK) {
                    Toast.makeText(context, "get" + context.getString(R.string.url_return_code_err) + statusCode, Toast.LENGTH_LONG).show();
                }
                responseBody = httpGet.getResponseBodyAsString();
                //System.out.println("XMLDATA=====>"+responseBody);
                break;
            } catch (HttpException e) {
                time++;
                if (time < RETRY_TIME) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e1) {
                    }
                    continue;
                }
                // 发生致命的异常，可能是协议不对或者返回的内容有问题
                e.printStackTrace();
                Toast.makeText(context, "get" + context.getString(R.string.url_protocol_or_returndata_error), Toast.LENGTH_LONG).show();
            } catch (IOException e) {
                time++;
                if (time < RETRY_TIME) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e1) {
                    }
                    continue;
                }
                // 发生网络异常
                e.printStackTrace();
                Toast.makeText(context, context.getString(R.string.net_error), Toast.LENGTH_LONG).show();
            } finally {
                // 释放连接
                httpGet.releaseConnection();
                httpClient = null;
            }
        } while (time < RETRY_TIME);

        responseBody = responseBody.replace('', '?');

        return new ByteArrayInputStream(responseBody.getBytes());
    }

    /**
     * 公用post方法
     *
     * @param url
     * @param params
     * @param files
     */
    public static InputStream _post(Context context, String url, Map<String, Object> params, Map<String, File> files) {
        //System.out.println("post_url==> "+url);
//		String cookie = getCookie(appContext);
        String userAgent = getUserAgent(context);

        HttpClient httpClient = null;
        PostMethod httpPost = null;

        //post表单参数处理
        int length = (params == null ? 0 : params.size()) + (files == null ? 0 : files.size());
        Part[] parts = new Part[length];
        int i = 0;
        if (params != null)
            for (String name : params.keySet()) {
                parts[i++] = new StringPart(name, String.valueOf(params.get(name)), UTF_8);
                //System.out.println("post_key==> "+name+"    value==>"+String.valueOf(params.get(name)));
            }
        if (files != null)
            for (String file : files.keySet()) {
                try {
                    parts[i++] = new FilePart(file, files.get(file));
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
                //System.out.println("post_key_file==> "+file);
            }

        String responseBody = "";
        int time = 0;
        do {
            try {
                httpClient = getHttpClient();
                httpPost = getHttpPost(context, url, "", userAgent);
                httpPost.setRequestEntity(new MultipartRequestEntity(parts, httpPost.getParams()));
                int statusCode = httpClient.executeMethod(httpPost);
                if (statusCode != HttpStatus.SC_OK) {
                    Toast.makeText(context, "post" + context.getString(R.string.url_return_code_err) + statusCode, Toast.LENGTH_LONG).show();
                }
                //暂无cookie
//		        else if(statusCode == HttpStatus.SC_OK)
//		        {
//		            Cookie[] cookies = httpClient.getState().getCookies();
//		            String tmpcookies = "";
//		            for (Cookie ck : cookies) {
//		                tmpcookies += ck.toString()+";";
//		            }
//		            //保存cookie
//	        		if(appContext != null && tmpcookies != ""){
//	        			appContext.setProperty("cookie", tmpcookies);
//	        			appCookie = tmpcookies;
//	        		}
//		        }
                responseBody = httpPost.getResponseBodyAsString();
                //System.out.println("XMLDATA=====>"+responseBody);
                break;
            } catch (HttpException e) {
                time++;
                if (time < RETRY_TIME) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e1) {
                    }
                    continue;
                }
                // 发生致命的异常，可能是协议不对或者返回的内容有问题
                e.printStackTrace();
                Toast.makeText(context, "post" + context.getString(R.string.url_protocol_or_returndata_error), Toast.LENGTH_LONG).show();
            } catch (IOException e) {
                time++;
                if (time < RETRY_TIME) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e1) {
                    }
                    continue;
                }
                // 发生网络异常
                e.printStackTrace();
                Toast.makeText(context, context.getString(R.string.net_error), Toast.LENGTH_LONG).show();
            } finally {
                // 释放连接
                httpPost.releaseConnection();
                httpClient = null;
            }
        } while (time < RETRY_TIME);

        responseBody = responseBody.replace('', '?');

        return new ByteArrayInputStream(responseBody.getBytes());
    }

}